﻿//  --------------------------------
//  Copyright (c) AW Systems, Inc. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.codeplex.com/SLAM/license
//  ---------------------------------

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;
using Slam;
using Slam.Configuration;
using StructureMap;
using StructureMap.Pipeline;
using StructureMap.Configuration.DSL;
using StructureMap.Attributes;
using System.Xml;
using System.Xml.Linq;
using Microsoft.SharePoint;
using Slam.Internal;

namespace Slam.StructureMap
{
	public class ComponentFactory : IComponentFactory
	{
		private static bool configured = false;

		public ComponentFactory()
		{
			Initialize();
		}

		private void Initialize()
		{
			if (!configured)
			{
				//Register defaults
				SlamRegistry registry = new SlamRegistry();
				ObjectFactory.Initialize(
					container =>
					{
						container.AddRegistry(registry);
					});

				//Register default Profiles
				DefaultContentTypeProfile contentTypeProfile = new DefaultContentTypeProfile();
				contentTypeProfile.CreateProfile(registry, "DefaultContentType");

				DefaultListTypeProfile listProfile = new DefaultListTypeProfile();
				listProfile.CreateProfile(registry, "DefaultList");

				//Register custom Profiles
				IConfigurationManager configuration = ObjectFactory.GetInstance<IConfigurationManager>();
				configuration.RegisterSection("TypeProfiles",
					config =>
					{
						object section = null;
						if (config is XDocument)
						{
							section = new XmlTypeProfileSection((XDocument)config);
						}
						return section;
					});

				XmlTypeProfileSection profileSection = configuration.GetSection<XmlTypeProfileSection>("TypeProfiles");

				foreach (CustomTypeProfile typeProfile in profileSection.GetCustomTypeProfiles())
				{
					try
					{
						ITypeProfile profileObject = Type.GetType(typeProfile.AssemblyQualifiedTypeName).CreateInstance<ITypeProfile>();
						if (profileObject != null)
						{
							profileObject.CreateProfile(registry, typeProfile.Name);
						}
					}
					catch(Exception ex) 
					{
						throw new Exception("Unable to load assembly for Type Profile: " + typeProfile.Name + ", " + typeProfile.AssemblyQualifiedTypeName + Environment.NewLine + ex.ToString());
					}
				}

				//Reset Plugin Graph
				ObjectFactory.Initialize(
					container =>
					{
						container.AddRegistry(registry);
					});

				//Get the instance again
				configuration = ObjectFactory.GetInstance<IConfigurationManager>();
				configuration.RegisterSection("TypeProfiles",
					config =>
					{
						object section = null;
						if (config is XDocument)
						{
							section = new XmlTypeProfileSection((XDocument)config);
						}
						return section;
					});
				configured = true;
			}
		}

		#region IComponentFactory Members

		public T GetInstance<T>()
		{
			return ObjectFactory.GetInstance<T>();
		}

        public T GetInstance<T>(string siteCollectionUrl)
        {   
            return ObjectFactory.GetInstance<T>();
        }

		public T GetInstance<T>(string siteCollection, string site, string typeName)
		{
			IConfigurationManager configuration = ObjectFactory.GetInstance<IConfigurationManager>();
			XmlTypeProfileSection profileSection = configuration.GetSection<XmlTypeProfileSection>("TypeProfiles");
			ObjectFactory.Profile = profileSection.GetTypeProfileName(siteCollection, site, "", typeName);
			return ObjectFactory.GetInstance<T>();
		}

		public T GetInstance<T>(string siteCollection, string site, string id, string typeName)
		{
			IConfigurationManager configuration = ObjectFactory.GetInstance<IConfigurationManager>();
			XmlTypeProfileSection profileSection = configuration.GetSection<XmlTypeProfileSection>("TypeProfiles");
			ObjectFactory.Profile = profileSection.GetTypeProfileName(siteCollection, site, id, typeName);
			return ObjectFactory.GetInstance<T>();
		}

		public void ResetContainer()
		{
			configured = false;
			Initialize();
		}

		#endregion
	}
}
